/**
 * The handler package.
 */
package fr.umlv.m2.ig.handler;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import fr.umlv.m2.ig.model.Line;
import fr.umlv.m2.ig.model.LineBuilder;
import fr.umlv.m2.ig.model.Station;
import fr.umlv.m2.ig.model.StationOrCurveBuilder;
import fr.umlv.m2.ig.model.StationType;

/**
 * This class defines the XML handler for the XML map file.
 * 
 * @author Gambouele Bertrand.
 * @author Viravout Alexandre.
 */
public class XMLMapHandler extends DefaultHandler {
  
	/**
	 * Map of lines.
	 */
	private final Map<String, Line> lines;

	/**
	 * Map of stations and curves.
	 */
	private final SortedMap<String, Station> stationsAndCurve;

	/**
	 * Name of the current line.
	 */
	private String currentLineName;

  /**
   * Name of the current station.
   */
  private String currentStationOrCurveName;

	/**
	 * Current builder for a {@code Line} object.
	 */
	private LineBuilder currentLineBuilder;

	/**
	 * Current builder for a {@code Station} object.
	 */
	private StationOrCurveBuilder currentStationOrCurveBuilder;

	/**
	 * The map width.
	 */
	private int width;

	/**
	 * The map height.
	 */
	private int height;

	/**
	 * Creates a new {@code XMLMapHandler} object.
	 */
	public XMLMapHandler() {
	  this.lines = new LinkedHashMap<String, Line>();
	  this.stationsAndCurve = new TreeMap<String, Station>();
	}

	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		if ("map".equals(qName)) {
			this.width = Integer.valueOf(attributes.getValue("width"));
			this.height = Integer.valueOf(attributes.getValue("height"));
			
		} else if ("line".equals(qName)) {
		  this.currentLineName = attributes.getValue("name");

		  this.currentLineBuilder = new LineBuilder();
		  this.currentLineBuilder.setName(this.currentLineName);
		  
		} else if ("journey".equals(qName)) {
			String origin = attributes.getValue("origin");
			String destination = attributes.getValue("destination");
			
			this.currentLineBuilder.addJourney(origin, destination);
			
		} else if (("station".equals(qName)) || ("curve".equals(qName))) {
		  this.currentStationOrCurveName = attributes.getValue("name");

			if (this.stationsAndCurve.containsKey(this.currentStationOrCurveName)) {
			  this.currentStationOrCurveBuilder = new StationOrCurveBuilder(this.stationsAndCurve.get(this.currentStationOrCurveName));
			} else {
			  if("curve".equals(qName)) {
          this.currentStationOrCurveBuilder = new StationOrCurveBuilder(this.currentStationOrCurveName, StationType.CURVE);
			  } else {
			    this.currentStationOrCurveBuilder = new StationOrCurveBuilder(this.currentStationOrCurveName, StationType.STATION);
			  }
			}
			
		} else if ("coord".equals(qName)) {
			int x = Integer.parseInt(attributes.getValue("x"));
			int y = Integer.parseInt(attributes.getValue("y"));
			
			this.currentStationOrCurveBuilder.setCoordinates(this.currentLineName, x, y);
			
		} else if ("next".equals(qName)) {
			String destination = attributes.getValue("destination");
			String nextStation = attributes.getValue("station");
			
			this.currentStationOrCurveBuilder.addEdge(this.currentLineName, destination, nextStation);
		}
	}

	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		if ("line".equals(qName)) {
			this.lines.put(this.currentLineName, this.currentLineBuilder.getLine());
		} else if ("station".equals(qName)) {
		  this.stationsAndCurve.put(this.currentStationOrCurveName, this.currentStationOrCurveBuilder.getStation());
		} else if ("curve".equals(qName)) {
		  this.stationsAndCurve.put(this.currentStationOrCurveName, this.currentStationOrCurveBuilder.getStation());
		}
	}

	/**
	 * Gets the map of lines.
	 * 
	 * @return map of lines.
	 */
	public Map<String, Line> getLines() {
		return this.lines;
	}

	/**
	 * Gets the map of stations and curves.
	 * 
	 * @return map of stations and curves.
	 */
	public SortedMap<String, Station> getStations() {
		return this.stationsAndCurve;
	}

	/**
	 * Gets the map width.
	 * 
	 * @return map width.
	 */
	public int getMapWidth() {
		return this.width;
	}

	/**
	 * Gets the map height.
	 * 
	 * @return map height.
	 */
	public int getMapHeight() {
		return this.height;
	}
}
